package model

import (
	"context"
	"fmt"
	"permis/ctrl"
	"strings"
	"time"

	"gitee.com/cloudapex/ulern/htp"
	"gitee.com/cloudapex/ulern/rds"
	"gitee.com/cloudapex/ulern/util"
	"google.golang.org/grpc/metadata"
	"xorm.io/xorm"
)

/*******************************************************************************
Copyright:cloud
Author:cloudapex@126.com
Version:1.0
Date:2020-07-09
Description: 公共数据
*******************************************************************************/

// => 注册表结构
func init() {
	ctrl.MDB.Sync(int(EMDB_Permt),
		&User{}, &UserRole{}, &UserGroup{}, &Group{}, &GroupRole{}, &Role{}, &RolePower{}, &Power{})
}

/*------------------------------------------------------------------------------
======================================常量=======================================
------------------------------------------------------------------------------*/
const (
	DEF_SECRET_OVER_S     = 30  // 请求有效时间30s内
	DEF_BAT_PAGE_SIZE     = 30  // 每页30条
	DEF_INSERT_BATCH_SIZE = 120 // 批量插入每批的量
)

var (
	// jwt key
	SignKey []byte = []byte("aldie33!@Dd$$%G&&#asd$^asd&*x%a%……334*")
)

/*------------------------------------------------------------------------------
======================================类型=======================================
------------------------------------------------------------------------------*/
// => 数据库连接类型
type EMDB int //
const (
	EMDB_Permt EMDB = iota // 权限数据库
	EMDB_Max
)

func MDB(e EMDB) *xorm.Engine {
	return ctrl.MDB.Use(int(e))
}

// => 缓存库连接类型
type ERDB int //
const (
	ERDB_Permt ERDB = iota // 权限缓存库
	ERDB_Max
)

func RDB(e ERDB) *rds.Pool {
	return ctrl.RDB.Use(int(e))
}

// => 菜单类型
type EPower int //
const (
	EPower_Menu EPower = iota + 1 // 菜单
	EPower_Func                   // 功能
	EPower_Data                   // 数据
	EPower_Max
) //
func (e EPower) String() string {
	switch e {
	case EPower_Menu:
		return "菜单"
	case EPower_Func:
		return "功能"
	case EPower_Data:
		return "数据"
	}
	return fmt.Sprintf("EPower_unknow(%d)", e)
}

// => 树节点类型
type ETreeNode int //
const (
	ETreeNode_Base ETreeNode = iota + 1 // 子节点
	ETreeNode_Leaf                      // 叶节点
	ETreeNode_Max
) //
func (e ETreeNode) String() string {
	switch e {
	case ETreeNode_Base:
		return "子节点"
	case ETreeNode_Leaf:
		return "叶节点"
	}
	return fmt.Sprintf("ETreeNode_unknow(%d)", e)
}

// => 时间字段类型
type ETimeField int //
const (
	ETF_Unix   ETimeField = iota // unix
	ETF_Format                   // string_format
)

// => 记录状态类型
type EStateField = int32 //
const (
	EState_Enable EStateField = iota + 1 // 有效
	EState_Unable                        // 无效
)

/*------------------------------------------------------------------------------
======================================结构=======================================
------------------------------------------------------------------------------*/

// ----- UserTokenInfo

// 载荷，可以加一些自己需要的信息
type UserTokenInfo struct {
	UId   int64  // 用户Id
	GId   int64  // 组ID
	PId   int64  // 项目ID
	RId   int64  // 角色ID
	Name  string // 姓名
	Phone string // 用户手机号
} //
func (c *UserTokenInfo) Valid() bool {
	return true
}
func CurrUser(ctx context.Context) *UserTokenInfo {
	return ctx.Value(htp.DEF_CLAIMS_HEAD_KEY).(*UserTokenInfo)
}
func CurrHead(ctx context.Context, key string) string {
	md, ok := metadata.FromIncomingContext(ctx)
	if !ok {
		return ""
	}
	return strings.Join(md.Get(key), " ")
}

// ----- SortFinder
type SortFinder struct {
	Order int `form:"order" json:"order" binding:"omitempty"` // 排序字段(根据后端定义的1,2..数字含义排列,当数字不匹配时,数据端按默认排序字段处理)
	Orule int `form:"orule" json:"orule" binding:"omitempty"` // 0:倒序; 1:正序; (数据端为: 1:倒序,2:升序)
}

func (this *SortFinder) condis(q *xorm.Session, tbl, defaultOrderField string, orderFields map[int]string) *xorm.Session {
	contain, order := false, ""
	util.Cast(tbl != "", func() { tbl += "." }, nil)
	util.Cast(orderFields != nil, func() { _, contain = orderFields[this.Order] }, nil)
	util.Cast(this.Order != 0 && !contain, func() { order = "" }, nil)
	util.Cast(contain, func() { order = orderFields[this.Order] }, nil)
	util.Cast(order == "", func() { order = defaultOrderField }, nil)
	util.Cast(this.Orule == 0, func() { q = q.Desc(tbl + order) }, func() { q = q.Asc(tbl + order) })
	return q
}

// ----- PageFinder
type CTimeField struct {
	typ  ETimeField
	name string
}
type PageFinder struct {
	Pnum int          `form:"pnum" json:"pnum" binding:"required,min=3,max=100"` // 单页数量
	Page int          `form:"page" json:"page" binding:"required"`               // 页码
	Bgn  int64        `form:"bgn" json:"bgn" binding:"omitempty"`                // 开始时间(int)
	End  int64        `form:"end" json:"end" binding:"omitempty"`                // 结束时间(int)(二选一)
	BgnS util.TJsTime `form:"bgnS" json:"bgnS" binding:"omitempty"`              // 开始时间(string)
	EndS util.TJsTime `form:"endS" json:"endS" binding:"omitempty"`              // 结束时间(string)(二选一)
}

func (this *PageFinder) condis(q *xorm.Session, tf *CTimeField) *xorm.Session {
	if tf != nil {
		var _bgn, _end interface{}

		if this.Bgn != 0 || this.End != 0 {
			_bgn, _end = this.Bgn, this.End
			util.Cast(tf.typ == ETF_Format, func() { _bgn, _end = time.Unix(this.Bgn, 0), time.Unix(this.End, 0) }, nil)
		} else if !time.Time(this.BgnS).IsZero() || !time.Time(this.EndS).IsZero() {
			_bgn, _end = this.BgnS, this.EndS
			util.Cast(tf.typ == ETF_Unix, func() { _bgn, _end = this.BgnS.ToTime().Unix(), this.EndS.ToTime().Unix() }, nil)
		}

		util.Cast(_bgn != nil || _end != nil, func() { q = q.Where(fmt.Sprintf("%s >= ? and %s < ?", tf.name, tf.name), _bgn, _end) }, nil)
	}

	this.Page--
	return q.Limit(this.Pnum, this.Page*this.Pnum)
}

/*------------------------------------------------------------------------------
======================================方法=======================================
------------------------------------------------------------------------------*/

// 组合节点路径
func NodePath(parentPath string, parentId int64) string {
	if parentId == 0 {
		return "0"
	}
	return fmt.Sprintf("%s/%d", parentPath, parentId)
}
